home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Snippets / PNL Libraries / MyWindows.p < prev    next >
Encoding:
Text File  |  1997-05-07  |  18.5 KB  |  550 lines  |  [TEXT/CWIE]

  1. unit MyWindows;
  2.  
  3. { Based heavilly on Dean Yu's Develop #17 code }
  4.  
  5. interface
  6.  
  7.     uses
  8.         Types, Windows, Quickdraw, MyAssertions;
  9.  
  10.     const
  11.         document_titlebar_height = 18;
  12.         
  13. {$ifc not do_debug}
  14. {$definec AssertValidWindow(w)}
  15. {$elsec}
  16. {$definec AssertValidWindow(w) AssertValidWindowCode(w)}
  17. {$endc}
  18.  
  19. {$ifc do_debug}
  20.     procedure AssertValidWindowCode(window: WindowPtr);
  21. {$endc}
  22.  
  23.     procedure ZoomTheWindow (window: WindowPtr; zoomout: boolean; idealsize: Point; var unzoomed: Rect);
  24.     procedure ZoomWindowOut (window: WindowPtr; titlebar_height:integer; idealsize: Point);
  25.     procedure GetWindowRect (window: WindowPtr; var r: Rect);
  26.     procedure SetWindowRect (window: WindowPtr; const r: Rect);
  27.     procedure GetWindowPosition(window:WindowPtr; var pos:Point);
  28.     procedure SetWindowPosition(window:WindowPtr; pos:Point);
  29.     function GetWindowContentRegion (window: WindowPtr): RgnHandle;
  30.     function GetWindowStructureRegion (window: WindowPtr): RgnHandle;
  31.     procedure GetWindowPortRect (window: WindowPtr; var portRect: Rect);
  32.     function GetWindowVisible (window: WindowPtr): boolean;
  33.     procedure GetWindowStandardState (window: WindowPtr; var standardState: Rect);
  34.     procedure SetWindowStandardState (window: WindowPtr; standardState: Rect);
  35.     procedure GetWindowUserState (window: WindowPtr; var userState: Rect);
  36.     procedure SetWindowUserState (window: WindowPtr; userState: Rect);
  37.     function TitleBarOnScreen (window: WindowPtr): boolean;
  38.     procedure GetBestScreenRect(windowBounds: Rect; var screenRect:Rect; var on_main_device:boolean);
  39.     function IsWindowShaded(window: WindowPtr): boolean;
  40.     function WindowInWindowList (window: WindowPtr): boolean;
  41.     procedure StaggerWindow( window: WindowPtr );
  42.     function FrontWindowList: WindowPtr;
  43.     function NextWindowList( window: WindowPtr ): WindowPtr;
  44.     procedure CenterWindow( window: WindowPtr; center: Rect );
  45.     
  46. implementation
  47.  
  48. { Based on code by Dean Yu in Develop 17 }
  49. { Changes: }
  50. { Converted to Pascal }
  51. { Pass in desired window size instead of a ProcPtr to return the desired window size }
  52. { Removed use of DeviceLoop }
  53. {   (DeviceLoop is System 7 dependent, and doesn't work in THINK Pascal anyway due to a bug in the interfaces }
  54. { Improved to Handle zooming windows before they are made visible (since struct and content rgn's are empty) }
  55.  
  56.     uses
  57.         Script, LowMem, 
  58.         MyTypes, MySystemGlobals, MyMathUtils, MyAssertions,
  59.         MyUtils; { delete MyUtils }
  60.  
  61.     const
  62.         kNudgeSlop = 4;
  63.         kIconSpace = 64;
  64.  
  65. {$ifc undefined allow_windows_not_in_window_list}
  66. {$setc allow_windows_not_in_window_list := false}
  67. {$endc}
  68.  
  69. { WindowRecord accessor functions }
  70.  
  71. {$ifc do_debug}
  72.     procedure AssertValidWindowCode(window: WindowPtr);
  73. {$ifc not allow_windows_not_in_window_list}
  74.         var
  75.             nw: WindowPtr;
  76. {$endc}
  77.     begin
  78.         Assert( window <> nil );
  79. {$ifc not allow_windows_not_in_window_list}
  80.         nw := FrontWindowList;
  81.         while (nw <> nil) & (window <> nw) do begin
  82.             nw := WindowPtr( WindowPeek(nw)^.nextWindow );
  83.         end;
  84.         Assert( nw <> nil );
  85. {$endc}
  86.     end;
  87. {$endc}
  88.     
  89.     function GetWindowContentRegion (window: WindowPtr): RgnHandle;
  90.     begin
  91.         AssertValidWindow( window );
  92.         GetWindowContentRegion := WindowPeek(window)^.contRgn;
  93.     end;
  94.  
  95.     function GetWindowStructureRegion (window: WindowPtr): RgnHandle;
  96.     begin
  97.         AssertValidWindow( window );
  98.         GetWindowStructureRegion := WindowPeek(window)^.strucRgn;
  99.     end;
  100.  
  101.     procedure GetWindowPortRect (window: WindowPtr; var portRect: Rect);
  102.     begin
  103.         AssertValidWindow( window );
  104.         portRect := WindowPeek(window)^.port.portRect;
  105.     end;
  106.  
  107.     function GetWindowVisible (window: WindowPtr): boolean;
  108.     begin
  109.         AssertValidWindow( window );
  110.         GetWindowVisible := WindowPeek(window)^.visible;
  111.     end;
  112.  
  113.     procedure GetWindowStandardState (window: WindowPtr; var standardState: Rect);
  114.     begin
  115.         AssertValidWindow( window );
  116.         Assert( WindowPeek(window)^.dataHandle <> nil );
  117.         standardState := WStateDataHandle(WindowPeek(window)^.dataHandle)^^.stdState;
  118.     end;
  119.  
  120.     procedure SetWindowStandardState (window: WindowPtr; standardState: Rect);
  121.     begin
  122.         AssertValidWindow( window );
  123.         Assert( WindowPeek(window)^.dataHandle <> nil );
  124.         WStateDataHandle(WindowPeek(window)^.dataHandle)^^.stdState := standardState;
  125.     end;
  126.  
  127.     procedure GetWindowUserState (window: WindowPtr; var userState: Rect);
  128.     begin
  129.         AssertValidWindow( window );
  130.         Assert( WindowPeek(window)^.dataHandle <> nil );
  131.         userState := WStateDataHandle(WindowPeek(window)^.dataHandle)^^.userState;
  132.     end;
  133.  
  134.     procedure SetWindowUserState (window: WindowPtr; userState: Rect);
  135.     begin
  136.         AssertValidWindow( window );
  137.         Assert( WindowPeek(window)^.dataHandle <> nil );
  138.         WStateDataHandle(WindowPeek(window)^.dataHandle)^^.userState := userState;
  139.     end;
  140.  
  141.     procedure GetWindowRect (window: WindowPtr; var r: Rect);
  142.     begin
  143.         AssertValidWindow( window );
  144.         SetPort(window);
  145.         GetWindowPortRect(window, r);
  146.         LocalToGlobal(r.topLeft);
  147.         LocalToGlobal(r.botRight);
  148.     end;
  149.  
  150.     procedure SetWindowRect (window: WindowPtr; const r: Rect);
  151.     begin
  152.         AssertValidWindow( window );
  153.         MoveWindow(window,r.left,r.top,false);
  154.         SizeWindow(window,r.right-r.left,r.bottom-r.top,true);
  155.     end;
  156.  
  157.     procedure GetWindowPosition(window:WindowPtr; var pos:Point);
  158.         var
  159.             r:Rect;
  160.     begin
  161.         AssertValidWindow( window );
  162.         SetPort(window);
  163.         GetWindowPortRect(window, r);
  164.         pos:=r.topLeft;
  165.         LocalToGlobal(pos);
  166.     end;
  167.     
  168.     procedure SetWindowPosition(window:WindowPtr; pos:Point);
  169.         var
  170.             r:Rect;
  171.     begin
  172.         AssertValidWindow( window );
  173.         SetPort(window);
  174.         GetWindowPortRect(window, r);
  175.         OffsetRect(r,-r.left+pos.h,-r.top+pos.v);
  176.         SetWindowRect(window,r);
  177.     end;
  178.     
  179.     function GetBestDevice (windowBounds: Rect): GDHandle;
  180.         var
  181.             thisGD, bestGD: GDHandle;
  182.             thisArea, bestArea: longint;
  183.             thisBounds: Rect;
  184.             dummy: boolean;
  185.     begin
  186.         thisGD := GetDeviceList;
  187.         bestArea := 0;
  188.         bestGD := GetMainDevice;
  189.         while thisGD <> nil do begin
  190.             if TestDeviceAttribute(thisGD, screenDevice) & TestDeviceAttribute(thisGD, screenActive) then begin
  191.                 dummy := SectRect(windowBounds, thisGD^^.gdRect, thisBounds);
  192.                 thisArea := longint(thisBounds.right - thisBounds.left) * longint(thisBounds.bottom - thisBounds.top);
  193.                 if thisArea > bestArea then begin
  194.                     bestGD := thisGD;
  195.                     bestArea := thisArea;
  196.                 end;
  197.             end;
  198.             thisGD := GetNextDevice(thisGD);
  199.         end;
  200.         GetBestDevice := bestGD;
  201.     end;
  202.  
  203.     procedure GetBestScreenRect(windowBounds: Rect; var screenRect:Rect; var on_main_device:boolean);
  204.     { NOTE: screenRect will not include the menu bar }
  205.         var
  206.             screenWithLargestPartOfWindow: GDHandle;        
  207.     begin
  208.         if has_ColourQuickDraw then begin
  209.             screenWithLargestPartOfWindow := GetBestDevice(windowBounds);
  210.             screenRect := screenWithLargestPartOfWindow^^.gdRect;
  211.             on_main_device := GetMainDevice = screenWithLargestPartOfWindow;
  212.         end else begin
  213.             screenRect := GetQDGlobals^.screenBits.bounds;
  214.             on_main_device := true;
  215.         end;
  216.         if on_main_device then begin
  217.             screenRect.top := screenRect.top + LMGetMBarHeight;
  218.         end;
  219.     end;
  220.  
  221. { Figure out how much we need to move the window to get it entirely on the monitor.  If }
  222. { the window wouldn’t fit completely on the monitor anyway, don’t move it at all; we’ll }
  223. { make it fit later on. }
  224.  
  225.     function CalculateOffsetAmount (idealStartPoint, idealEndPoint, idealOnScreenStartPoint, idealOnScreenEndPoint, screenEdge1, screenEdge2: integer): integer;
  226.         var
  227.             offsetAmount: integer;
  228.     begin
  229.     { First check to see if the window fits on the screen in this dimension. }
  230.         if (idealStartPoint < screenEdge1) & (idealEndPoint > screenEdge2) then begin
  231.             offsetAmount := 0;
  232.         end else begin
  233.  
  234.         { Find out how much of the window lies off this screen by subtracting the amount of the window }
  235.         { that is on the screen from the size of the entire window in this dimension. If the window }
  236.         { is completely offscreen, the offset amount is going to be the distance from the ideal }
  237.         { starting Point to the first edge of the screen. }
  238.             if idealOnScreenStartPoint - idealOnScreenEndPoint = 0 then begin
  239.             { See if the window is lying to the left or above the screen }
  240.                 if idealEndPoint < screenEdge1 then begin
  241.                     offsetAmount := screenEdge1 - idealStartPoint + kNudgeSlop;
  242.                 end else begin
  243.             { Otherwise, it’s below or to the right of the screen }
  244.                     offsetAmount := screenEdge2 - idealEndPoint - kNudgeSlop;
  245.                 end;
  246.             end else begin
  247.             { Window is already partially or completely on the screen }
  248.                 offsetAmount := (idealEndPoint - idealStartPoint) - (idealOnScreenEndPoint - idealOnScreenStartPoint);
  249.  
  250.             { If we are offscreen a little, move the window in a few more pixels from the edge of the screen. }
  251.                 if offsetAmount <> 0 then begin
  252.                     offsetAmount := offsetAmount + kNudgeSlop;
  253.                 end;
  254.  
  255.             { Check to see which side of the screen the window was falling off of, so that it can be }
  256.             { nudged in the opposite direction. }
  257.                 if idealEndPoint > screenEdge2 then begin
  258.                     offsetAmount := -offsetAmount;
  259.                 end;
  260.             end;
  261.         end;
  262.  
  263.         CalculateOffsetAmount := offsetAmount;
  264.     end;
  265.  
  266.     procedure AddRect (r1, r2: Rect; var r: Rect);
  267.     begin
  268.         r.top := r1.top + r2.top;
  269.         r.bottom := r1.bottom + r2.bottom;
  270.         r.left := r1.left + r2.left;
  271.         r.right := r1.right + r2.right;
  272.     end;
  273.  
  274.     procedure SubRect (r1, r2: Rect; var r: Rect);
  275.     begin
  276.         r.top := r1.top - r2.top;
  277.         r.bottom := r1.bottom - r2.bottom;
  278.         r.left := r1.left - r2.left;
  279.         r.right := r1.right - r2.right;
  280.     end;
  281.  
  282.     procedure ZoomWindowOut (window: WindowPtr; titlebar_height:integer; idealsize: Point);
  283.         var
  284.             windowBounds: Rect;
  285.             newStandardRect: Rect;
  286.             scratchRect: Rect;
  287.             screenRect: Rect;
  288.             portRect: Rect;
  289.             contentRegionBoundingBox: Rect;
  290.             structureRegionBoundingBox: Rect;
  291.             scratchRegion: RgnHandle;
  292.             structureRegion: RgnHandle;
  293.             contentRegion: RgnHandle;
  294.             on_main_device: boolean;
  295.             horizontalAmountOffScreen: integer;
  296.             verticalAmountOffScreen: integer;
  297.             windowFrame: Rect;
  298.             dummy: boolean;
  299.             orgrect: Rect;
  300.     begin
  301.         AssertValidWindow( window );
  302.         SetPort(window);
  303.  
  304.         GetWindowRect(window, orgrect);
  305.  
  306.         contentRegion := GetWindowContentRegion(window);
  307.         structureRegion := GetWindowStructureRegion(window);
  308.         GetWindowPortRect(window, portRect);
  309.  
  310. { If the window is invisible (or at least initially before it is ever made visible), then the content and structure }
  311. { regions will be empty.  In this case, we fake it out by using the portRect as the content region and 18 (hardcoded) }
  312. { as the titlebar height }
  313.         if EmptyRgn(structureRegion) then begin
  314.             GetWindowRect(window, scratchRect);
  315.             contentRegionBoundingBox := scratchRect;
  316.             scratchRect.top := scratchRect.top - titlebar_height; { No other way of figuring out the window frame }
  317.             structureRegionBoundingBox := scratchRect;
  318.         end else begin
  319.             contentRegionBoundingBox := contentRegion^^.rgnBBox;
  320.             structureRegionBoundingBox := structureRegion^^.rgnBBox;
  321.         end;
  322.  
  323.     { Determine the size of the window frame }
  324.         windowFrame.top := structureRegionBoundingBox.top - contentRegionBoundingBox.top;
  325.         windowFrame.left := structureRegionBoundingBox.left - contentRegionBoundingBox.left;
  326.         windowFrame.right := structureRegionBoundingBox.right - contentRegionBoundingBox.right;
  327.         windowFrame.bottom := structureRegionBoundingBox.bottom - contentRegionBoundingBox.bottom;
  328.  
  329.     { If the window is being zoomed into the standard state, calculate the best size }
  330.     { to display the window’s information. }
  331.         { Usually, we would use the content region’s bounding box to determine the monitor }
  332.         { with largest portion of the window’s area. However, if the entire content region }
  333.         { of the window is not on any screen, the structure region should be used instead. }
  334.         windowBounds := contentRegionBoundingBox;
  335.         scratchRegion := NewRgn;
  336.         RectRgn(scratchRegion, windowBounds);
  337.         SectRgn(GetGrayRgn, scratchRegion, scratchRegion);
  338.         if EmptyRgn(scratchRegion) then begin
  339.             windowBounds := structureRegionBoundingBox;
  340.         end;
  341.         DisposeRgn(scratchRegion);
  342.  
  343.         GetBestScreenRect(windowBounds,screenRect,on_main_device);
  344.  
  345.  
  346.         { Go figure out the perfect size for the window as if we had an infinitely large }
  347.         { screen }
  348.     {    (*calcRoutine)((WindowPtr) window, &newStandardRect);}
  349.         SetRect(newStandardRect, 0, 0, idealsize.h, idealsize.v);
  350.  
  351.         { Anchor the new rectangle at the window’s current top left corner }
  352.         { OffsetRect(&newStandardRect, -newStandardRect.left, -newStandardRect.top); }
  353.         OffsetRect(newStandardRect, orgrect.left, orgrect.top);
  354.  
  355.         { newStandardRect is the ideal size for the content area. The window frame }
  356.         { needs to be accounted for when we see if the window needs to be moved, }
  357.         { or resized, so add in the dimensions of the window frame.}
  358.         AddRect(newStandardRect, windowFrame, newStandardRect);
  359.  
  360. {        { If the new rectangle falls off the edge of the screen, nudge it so that it’s just }
  361.         { on the screen. CalculateOffsetAmount determines how much of the window is offscreen. }
  362.         dummy := SectRect(newStandardRect, screenRect, scratchRect);
  363.         if not EqualRect(newStandardRect, scratchRect) then begin
  364.             horizontalAmountOffScreen := CalculateOffsetAmount(newStandardRect.left, newStandardRect.right, scratchRect.left, scratchRect.right, screenRect.left, screenRect.right);
  365.             verticalAmountOffScreen := CalculateOffsetAmount(newStandardRect.top, newStandardRect.bottom, scratchRect.top, scratchRect.bottom, screenRect.top, screenRect.bottom);
  366.             OffsetRect(newStandardRect, horizontalAmountOffScreen, verticalAmountOffScreen);
  367.         end;
  368.  
  369.         { If we’re still falling off the edge of the screen, that means that the perfect }
  370.         { size is larger than the screen, so we need to shrink down the standard size }
  371.         dummy := SectRect(newStandardRect, screenRect, scratchRect);
  372.         if not EqualRect(newStandardRect, scratchRect) then begin
  373.  
  374.         { First shrink the width of the window. If the window is wider than the screen }
  375.         { it is zooming to, we can just pin the standard rectangle to the edges of the }
  376.         { screen, leaving some slop. If the window is narrower than the screen, we know }
  377.         { we just nudged it into position, so nothing needs to be done. }
  378.             if newStandardRect.right - newStandardRect.left > screenRect.right - screenRect.left then begin
  379.                 newStandardRect.left := screenRect.left + kNudgeSlop;
  380.  
  381.                 if (on_main_device) then begin
  382.                     newStandardRect.right := screenRect.right - kIconSpace;
  383.                 end else begin
  384.                     newStandardRect.right := screenRect.right - kNudgeSlop;
  385.                 end;
  386.             end;
  387.  
  388.             { Move in the top. Like the width of the window, nothing needs to be done unless }
  389.             { the window is taller than the height of the screen. }
  390.             if newStandardRect.bottom - newStandardRect.top > screenRect.bottom - screenRect.top then begin
  391.                 newStandardRect.top := screenRect.top + kNudgeSlop;
  392.                 newStandardRect.bottom := screenRect.bottom - kNudgeSlop;
  393.             end;
  394.         end;
  395.  
  396.         { We’ve got the best possible window position. Remove the }
  397.         { frame, slam it into the WStateData record and let ZoomWindow }
  398.         { take care of the rest. }
  399.         SubRect(newStandardRect, windowFrame, newStandardRect);
  400.  
  401.         if (newStandardRect.left = orgrect.left) & (newStandardRect.top = orgrect.top) then begin
  402.             SizeWindow(window, newStandardRect.right - newStandardRect.left, newStandardRect.bottom - newStandardRect.top, true);
  403.         end else begin
  404.             SetWindowRect(window, newStandardRect);
  405.         end;
  406. { If the window is still anchored at the current location, then just resize it }
  407.     end;
  408.  
  409.     procedure ZoomTheWindow (window: WindowPtr; zoomout: boolean; idealsize: Point; var unzoomed: Rect);
  410.     begin
  411.         AssertValidWindow( window );
  412.         SetPort(window);
  413.         if zoomout then begin
  414.             GetWindowRect(window, unzoomed);
  415.             ZoomWindowOut(window, document_titlebar_height, idealsize);
  416.         end else begin
  417.             SetWindowRect(window, unzoomed);
  418.         end;
  419.     end;
  420.  
  421.     function TitleBarOnScreen (window: WindowPtr): boolean;
  422.         var
  423.             rgn: RgnHandle;
  424.             r: Rect;
  425.             title: RgnHandle;
  426.     begin
  427.         AssertValidWindow( window );
  428.         rgn := NewRgn;
  429.         title := NewRgn;
  430.         CopyRgn(GetWindowStructureRegion(window), rgn);
  431.         GetWindowRect(window, r);
  432.         r.bottom := r.top;
  433.         r.top := r.top - document_titlebar_height;
  434.         InsetRect(r, 2, 2);
  435.         RectRgn(title, r);
  436.         if EmptyRgn( rgn ) then begin
  437.             UnionRgn(rgn, title, rgn);
  438.         end else begin
  439.             SectRgn(rgn, title, rgn);
  440.         end;
  441.         SectRgn(rgn, GetGrayRgn, rgn);
  442.         TitleBarOnScreen := not EmptyRgn(rgn);
  443.         DisposeRgn(title);
  444.         DisposeRgn(rgn);
  445.     end;
  446.  
  447.     function IsWindowShaded(window: WindowPtr): boolean;
  448.     begin
  449.         AssertValidWindow( window );
  450.         IsWindowShaded := EmptyRgn(GetWindowContentRegion(window));
  451.     end;
  452.     
  453.     function FrontWindowList: WindowPtr;
  454.     begin
  455.         FrontWindowList := WindowPtr(LMGetWindowList);
  456.     end;
  457.     
  458.     function NextWindowList( window: WindowPtr ): WindowPtr;
  459.     begin
  460.         AssertValidWindow( window );
  461.         NextWindowList := WindowPtr( WindowPeek(window)^.nextWindow );
  462.     end;
  463.     
  464.     function WindowInWindowList (window: WindowPtr): boolean;
  465.         var
  466.             nw: WindowPtr;
  467.     begin
  468.         AssertValidWindow( window );
  469.         nw := FrontWindowList;
  470.         while (nw <> nil) & (window <> nw) do begin
  471.             nw := NextWindowList( nw );
  472.         end;
  473.         WindowInWindowList := nw <> nil;
  474.     end;
  475.     
  476.     procedure StaggerWindow( window: WindowPtr );
  477.         const
  478.             start_v = 42;
  479.             start_h = 5;
  480.             rel_v = 20;
  481.             rel_h = 20;
  482.             finish_v = 10;
  483.             finish_h = 40;
  484.             max_slots_v = 100;
  485.             max_slots_h = 10;
  486.         var
  487.             mainr, wr: Rect;
  488.             slots_v, slots_h: integer;
  489.             counts: array[ 0..max_slots_v, 0..max_slots_h ] of integer;
  490.             nw: WindowPtr;
  491.             sv, sh: integer;
  492.             off_v, off_h: integer;
  493.             best_v, best_h, best: integer;
  494.     begin
  495.         AssertValidWindow( window );
  496.         GetWindowRect( window, wr );
  497.         mainr := GetMainDevice^^.gdRect;
  498.         slots_v := RectHeight( mainr ) - RectHeight( wr ) - start_v - finish_v;
  499.         slots_v := Min( Choose( slots_v < 0, 0, slots_v div rel_v ), max_slots_v );
  500.         slots_h := RectWidth( mainr ) - RectWidth( wr ) - start_h - finish_h;
  501.         slots_h := Min( Choose( slots_h < 0, 0, slots_h div rel_h ), max_slots_h );
  502.  
  503.         for sv := 0 to slots_v do begin
  504.             for sh := 0 to slots_h do begin
  505.                 counts[ sv, sh ] := 0;
  506.             end;
  507.         end;
  508.         
  509.         nw := FrontWindowList;
  510.         while (nw <> nil) do begin
  511.             if nw <> window then begin
  512.                 GetWindowRect( nw, wr );
  513.                 off_v := wr.top - mainr.top - start_v;
  514.                 off_h := wr.left - mainr.left - start_h;
  515.                 if (off_v >= 0) & (off_v mod rel_v = 0) & (off_h >= 0) & (off_h mod rel_h = 0) then begin
  516.                     off_v := off_v div rel_v;
  517.                     off_h := off_h div rel_h;
  518.                     if (off_v <= slots_v) & (off_h <= slots_h) then begin
  519.                         counts[ off_v, off_h ] := counts[ off_v, off_h ] + 1;
  520.                     end;
  521.                 end;
  522.             end;
  523.             nw := NextWindowList( nw );
  524.         end;
  525.         
  526.         best := maxint;
  527.         for sh := 0 to slots_h do begin
  528.             for sv := 0 to slots_v do begin
  529.                 off_h := (sh + sv) mod (slots_h + 1);
  530.                 if counts[ sv, off_h ] < best then begin
  531.                     best := counts[ sv, off_h ];
  532.                     best_v := sv;
  533.                     best_h := off_h;
  534.                 end; 
  535.             end;
  536.         end;
  537.         
  538.         MoveWindow( window, mainr.left + start_h + best_h*rel_h, mainr.top + start_v + best_v*rel_v, false );
  539.     end;
  540.  
  541.     procedure CenterWindow( window: WindowPtr; center: Rect );
  542.         var
  543.             frame: Rect;
  544.     begin
  545.         GetWindowRect( window, frame );
  546.         CenterRect( frame, center );
  547.         SetWindowRect( window, frame );
  548.     end;
  549.     
  550. end.